/**
 * 
 */
package com.feib.stms.util;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;

import com.feib.stms.model.LabelValue;
import com.feib.stms.model.Securities;
import com.feib.stms.model.UploadFile;
import com.feib.stms.service.SecuritiesService;

/**
 * @author Jimmy Liu
 *
 */
public class StmsUtil implements Serializable
{
	private static final long serialVersionUID = -8302822407738256034L;

	/**
	 * 券商權數
	 */
	protected static int SECURITIES_BASE_NUMBER = 12;

	/**
	 * 檔案類型
	 */
	private Map<String, LabelValue> fileFormatMap;

	private List<Securities> securities;

	/**
	 * 分公司資料</br>Key=母公司券商代號
	 */
	private Map<Long, Map<String, List<Securities>>> groupSecuritiesMap;

	private static StmsUtil instance = null;

	private StmsUtil(){}

	public static StmsUtil getInstance() {
		if (instance == null){
			synchronized(StmsUtil.class){
				if(instance == null) {
					instance = new StmsUtil();
				}
			}
		}
		return instance;
	}

	public Map<String, LabelValue> getFileFormatMap()
	{
		// TODO: 改抓DB與定時 refresh.
		if (null == this.fileFormatMap)
		{
			this.fileFormatMap = new LinkedHashMap<String, LabelValue>();

			LabelValue labelValue = new LabelValue();
			labelValue.setLabel("驗資資料");
			labelValue.setValue(UploadFile.UPLOAD_FILE_DELIVERY_PAYMENT_CHK);			
			this.fileFormatMap.put(UploadFile.UPLOAD_FILE_DELIVERY_PAYMENT_CHK, labelValue);			

			labelValue = new LabelValue();
			labelValue.setLabel("交割款資料");
			labelValue.setValue(UploadFile.UPLOAD_FILE_DELIVERY_PAYMENT);			
			this.fileFormatMap.put(UploadFile.UPLOAD_FILE_DELIVERY_PAYMENT, labelValue);		

			labelValue = new LabelValue();
			labelValue.setLabel("申購款資料");
			labelValue.setValue(UploadFile.UPLOAD_FILE_PURCHASE_PAYMENT);			
			this.fileFormatMap.put(UploadFile.UPLOAD_FILE_PURCHASE_PAYMENT, labelValue);		

			labelValue = new LabelValue();
			labelValue.setLabel("申購退款資料");
			labelValue.setValue(UploadFile.UPLOAD_FILE_PURCHASE_RETURN_PAYMENT);			
			this.fileFormatMap.put(UploadFile.UPLOAD_FILE_PURCHASE_RETURN_PAYMENT, labelValue);
		}

		return this.fileFormatMap;
	}

	public Collection<LabelValue> getUploadFileFormats()
	{
		return getFileFormatMap().values();
	}


	public void loadSecurities()
	{
		SecuritiesService securitiesService = (SecuritiesService)SpringContextUtil.getBean("securitiesService");
		securities = securitiesService.findAll();

		if (null == this.groupSecuritiesMap)
			this.groupSecuritiesMap = new LinkedHashMap<Long, Map<String,List<Securities>>>();
		else
			this.groupSecuritiesMap.clear();

		String key = null;
		boolean isParent = false;
		Securities parent = null;
		Long groupPk = null;
		List<Securities> data = null;
		for(Securities s: securities)
		{
			groupPk = s.getGroup().getGroupPk();

			Map<String,List<Securities>> securitiesMap = this.groupSecuritiesMap.get(groupPk);
			if (null == securitiesMap)
			{
				securitiesMap = new LinkedHashMap<String, List<Securities>>();
				this.groupSecuritiesMap.put(groupPk, securitiesMap);
			}

			parent = s.getParentSecurities();
			isParent = null == parent;						
			if (isParent)
			{
				key = s.getSecuritiesNo();
			}
			else
			{
				key = parent.getSecuritiesNo();
			}

			data = securitiesMap.get(key);
			if (null == data)
			{
				data = new ArrayList<Securities>();
				securitiesMap.put(key, data);
			}
			data.add(s);
		}
	}

	public Map<Long, Map<String, List<Securities>>>  getGroupSecuritiesMap()
	{
		if (null == groupSecuritiesMap)
			loadSecurities();
		return groupSecuritiesMap;

	}

	public Map<String, List<Securities>> getParentSecuritiesByGroupPk(Long groupPk)
	{
		return getGroupSecuritiesMap().get(groupPk);
	}

	public List<Securities> getSecuritiesByGroupPk(Long groupPk)
	{
		Map<String, List<Securities>> t = getGroupSecuritiesMap().get(groupPk);
		if (t == null)
			return null;

		List<Securities> result = new ArrayList<Securities>();
		Iterator<String> it = t.keySet().iterator();
		while( it.hasNext())
		{
			String parentSecuritiesNo = it.next();
			result.addAll(t.get(parentSecuritiesNo));
		}

		return result;		
	}


	/**
	 * 取得帳號檢查碼 M<br/>
	 * 存款帳號:
	 * <table BORDER="2">
	 * <tr><th>分行別</th><th>科目別</th><th>序號</th><th>檢碼</th></tr>
	 * <tr><td>N1&nbsp; N2&nbsp; N3</td><td>N4&nbsp; N5&nbsp; N6</td><td>N7&nbsp; N8&nbsp; N9&nbsp; N10&nbsp; N11&nbsp; N12&nbsp; N13</td><td>N14</td></tr>
	 * </table>
	 * 
	 * @param accountNo
	 * @return
	 */
	public int getAccountNoChecksum(String accountNo)
	{
		int checksum = 0;

		if (14 == StringUtils.length(accountNo))
		{
			char[] chars = accountNo.toCharArray();
			int a1 = CharUtils.toIntValue(chars[3]) * 5; //N4
			int a2 = CharUtils.toIntValue(chars[4]) * 9; //N5
			int a3 = CharUtils.toIntValue(chars[7]) * 1; //N8
			int a4 = CharUtils.toIntValue(chars[8]) * 4; //N9
			int a5 = CharUtils.toIntValue(chars[11]) * 7; //N12
			int a6 = CharUtils.toIntValue(chars[12]) * 8; //N13

			int x1 = a1 + a2 + a3 + a4 + a5 + a6;
			int x1mod = x1 % 11; // X  /  11 = 商及餘數
			int s1 = (11 - x1mod) %10; // 11 - 餘數 ﹦S1 (取個位)

			int b1 = CharUtils.toIntValue(chars[5]) * 8; //N6
			int b2 = CharUtils.toIntValue(chars[6]) * 7; //N7
			int b3 = CharUtils.toIntValue(chars[9]) * 4; //N10
			int b4 = CharUtils.toIntValue(chars[10]) * 1; //N11
			int b5 = CharUtils.toIntValue(chars[13]) * 5; //N14

			int x2 = b1 + b2 + b3 + b4 + b5;
			int x2mod = x2 % 11; // X  /  11 = 商及餘數
			int s2 = (11 - x2mod) %10; // 11 - 餘數 ﹦S2 (取個位)

			int y = s1 * 10 + s2; // Y = S1 (十位) 及 S2 (個位)

			//券商權數(二位)+ Y = 帳號檢查碼 (M) (取二位)
			checksum = (SECURITIES_BASE_NUMBER + y) % 100;
		}

		return checksum;
	}

	/**
	 * 淨收金額檢查碼 N<br/>
	 * 交易金額
	 * <table BORDER="2">
	 * <tr><td>N1&nbsp; N2&nbsp; N3&nbsp; N4&nbsp; N5&nbsp; N6&nbsp; N7&nbsp; N8&nbsp; N9&nbsp; N10&nbsp; N11&nbsp; N12&nbsp; N13</td></tr>
	 * </table>
	 * 
	 * @param netIncome
	 * @return
	 */
	public int getNetIncomeChecksum(String netIncome)
	{
		int checksum = 0;

		if (13 == StringUtils.length(netIncome)  &&  !"0000000000000".equals(netIncome))
		{
			char[] chars = netIncome.toCharArray();
			int a1 = CharUtils.toIntValue(chars[0]) * 5; //N1
			int a2 = CharUtils.toIntValue(chars[1]) * 7; //N2
			int a3 = CharUtils.toIntValue(chars[2]) * 8; //N3
			int a4 = CharUtils.toIntValue(chars[6]) * 8; //N7
			int a5 = CharUtils.toIntValue(chars[7]) * 4; //N8
			int a6 = CharUtils.toIntValue(chars[8]) * 1; //N9
			int a7 = CharUtils.toIntValue(chars[12]) * 3; //N13

			int x1 = a1 + a2 + a3 + a4 + a5 + a6 + a7;
			int x1mod = x1 % 11; // X  /  11 = 商及餘數
			int s3 = (11 - x1mod) %10; // 11 - 餘數 ﹦S3 (取個位)

			int b1 = CharUtils.toIntValue(chars[3]) * 3; //N4
			int b2 = CharUtils.toIntValue(chars[4]) * 1; //N5
			int b3 = CharUtils.toIntValue(chars[5]) * 9; //N6
			int b4 = CharUtils.toIntValue(chars[9]) * 4; //N10
			int b5 = CharUtils.toIntValue(chars[10]) * 8; //N11
			int b6 = CharUtils.toIntValue(chars[11]) * 8; //N12

			int x2 = b1 + b2 + b3 + b4 + b5 + b6;
			int x2mod = x2 % 11; // X  /  11 = 商及餘數
			int s4 = (11 - x2mod) %10; // 11 - 餘數 ﹦S4 (取個位)

			int y = s3 * 10 + s4; // Y = S3 (十位) 及 S4 (個位)

			//券商權數(二位)+ Y = 帳號檢查碼 (M) (取二位)
			checksum = (SECURITIES_BASE_NUMBER + y) % 100;
		}

		return checksum;
	}

	/**
	 * 淨付金額檢查碼 N<br/>
	 * 交易金額
	 * <table BORDER="2">
	 * <tr><td>N1&nbsp; N2&nbsp; N3&nbsp; N4&nbsp; N5&nbsp; N6&nbsp; N7&nbsp; N8&nbsp; N9&nbsp; N10&nbsp; N11&nbsp; N12&nbsp; N13</td></tr>
	 * </table>
	 * 
	 * @param netpay
	 * @return
	 */
	public int getNetPayChecksum(String netpay)
	{
		int checksum = 0;

		if (13 == StringUtils.length(netpay)  &&  !"0000000000000".equals(netpay))
		{
			char[] chars = netpay.toCharArray();
			int a1 = CharUtils.toIntValue(chars[0]) * 1; //N1
			int a2 = CharUtils.toIntValue(chars[1]) * 3; //N2
			int a3 = CharUtils.toIntValue(chars[2]) * 7; //N3
			int a4 = CharUtils.toIntValue(chars[6]) * 5; //N7
			int a5 = CharUtils.toIntValue(chars[7]) * 6; //N8
			int a6 = CharUtils.toIntValue(chars[8]) * 8; //N9
			int a7 = CharUtils.toIntValue(chars[12]) * 4; //N13

			int x1 = a1 + a2 + a3 + a4 + a5 + a6 + a7;
			int x1mod = x1 % 11; // X  /  11 = 商及餘數
			int s3 = (11 - x1mod) %10; // 11 - 餘數 ﹦S3 (取個位)

			int b1 = CharUtils.toIntValue(chars[3]) * 3; //N4
			int b2 = CharUtils.toIntValue(chars[4]) * 3; //N5
			int b3 = CharUtils.toIntValue(chars[5]) * 4; //N6
			int b4 = CharUtils.toIntValue(chars[9]) * 4; //N10
			int b5 = CharUtils.toIntValue(chars[10]) * 8; //N11
			int b6 = CharUtils.toIntValue(chars[11]) * 8; //N12

			int x2 = b1 + b2 + b3 + b4 + b5 + b6;
			int x2mod = x2 % 11; // X  /  11 = 商及餘數
			int s4 = (11 - x2mod) %10; // 11 - 餘數 ﹦S4 (取個位)

			int y = s3 * 10 + s4; // Y = S3 (十位) 及 S4 (個位)

			//券商權數(二位)+ Y = 帳號檢查碼 (M) (取二位)
			checksum = (SECURITIES_BASE_NUMBER + y) % 100;
		}

		return checksum;
	}

	/**
	 * 取得身分證檢查碼 M<br/>
	 * 身分證號:
	 * <table BORDER="2">
	 * <tr><th>英文</th><th>男女</th><th>序號</th></tr>
	 * <tr><td>N1</td><td>N2</td><td>N3&nbsp;  N4&nbsp; N5&nbsp; N6&nbsp; N7&nbsp; N8&nbsp; N9&nbsp; N10</td></tr>
	 * </table>
	 * 
	 * @param identifier
	 * @return
	 */
	public int getIdentifierChecksum(String identifier)
	{
		int checksum = 0;

		if (10 == StringUtils.length(identifier) )
		{
			char[] chars = identifier.toCharArray();
			int a1 = CharUtils.toIntValue(chars[1]) * 1; //N2
			int a2 = CharUtils.toIntValue(chars[2]) * 3; //N3
			int a3 = CharUtils.toIntValue(chars[5]) * 8; //N6

			int x1 = a1 + a2 + a3 ;
			int x1mod = x1 % 11; // X  /  11 = 商及餘數
			int s1 = (11 - x1mod) %10; // 11 - 餘數 ﹦S1 (取個位)

			int b1 = CharUtils.toIntValue(chars[3]) * 5; //N4
			int b2 = CharUtils.toIntValue(chars[4]) * 7; //N5
			int b3 = CharUtils.toIntValue(chars[6]) * 9; //N7

			int x2 = b1 + b2 + b3;
			int x2mod = x2 % 11; // X  /  11 = 商及餘數
			int s2 = (11 - x2mod) %10; // 11 - 餘數 ﹦S2 (取個位)

			int y = s1 * 10 + s2; // Y = S1 (十位) 及 S2 (個位)

			//券商權數(二位)+ Y = 帳號檢查碼 (M) (取二位)
			checksum = (SECURITIES_BASE_NUMBER + y) % 100;
		}

		return checksum;
	}

	/**
	 * 將身分證6-8碼以 *代替
	 * @param idno
	 * @return
	 */
	public String getIdMask(String idno)
	{
		if (StringUtils.isEmpty(idno))
			return "**********" ;

		char[] returnChars = new char[10];
		for(int i=0; i < 10; i++)
			returnChars[i] = '*';

		char[] chars = idno.toCharArray();

		for (int i=0; i < chars.length; i++)
		{
			if (i > 9)
				break;

			if (i >5 && i <9)
				continue;

			returnChars[i] = chars[i];          
		}

		return new String(returnChars);     
	}

	/**
	 * 將檢核碼以3碼為一組並以-符號隔開
	 * @param checksum
	 * @return
	 */
	public String getFormatChecksum(BigDecimal checksum)
	{
		if (null == checksum)
			return  "";

		String temp = String.valueOf(checksum);
		char[] chars = temp.toCharArray();

		StringBuffer returnValue = new StringBuffer();

		for (int i=0; i < chars.length; i++ )
		{
			if (i != 0 && 0 == i % 3)
				returnValue.append("-");
			returnValue.append(chars[i]);
		}

		return returnValue.toString();
	}

	
	/**
	 * 將交割帳號格式化
	 * AAABBBCCCCCCCD ===> AAA-BBB-CCCCCCC-D 
	 * @param preDesignatedAccount
	 * @return
	 */
	public String getFormatedPreDesignatedAccount(String preDesignatedAccount)
	{
		if (null == preDesignatedAccount)
			return  "";

		String temp = String.valueOf(preDesignatedAccount);
		
		char[] chars = temp.toCharArray();

		StringBuffer returnValue = new StringBuffer();

		for (int i=0; i < chars.length; i++ )
		{
			if (i == 3 || i == 6 || i == 13){
				returnValue.append("-");
			}
				
			returnValue.append(chars[i]);
		}

		return returnValue.toString();
	}
	
	
	public String getFormatChecksum(Long checksum)
	{
		if (null == checksum)
			return  "";

		return getFormatChecksum(new BigDecimal(checksum));
	}



}
